#include<iostream>
#include<string>
#include<boost/filesystem.hpp>
#include"tool.hpp"
#include<fstream>
using namespace boost ::filesystem;
using namespace std;

const string src_output="./data/raw_html";
const string src_input="./data/input";


typedef struct xt
{
    string title;
    string content;
    string url;
}x_t;


// //3个函数,前置声明
// bool em_in(vector<string>* x,const string &y){};
// bool em_analysis(const vector<string>&x,vector<x_t>*y){};
// bool em_out(vector<x_t>&x,const string&y){};

bool em_in(vector<string>* x,const string &y)
{
    path root_path(y);
    if(!exists(root_path))
    {
        cerr<<y<<"not exists"<<endl;
        return false;
    }
    //迭代
    recursive_directory_iterator end;
    for(recursive_directory_iterator iter(root_path);iter!=end;iter++)
    {
        if(!is_regular_file(*iter))
        {
            continue;
        }
        if(iter->path().extension()!=".html")
        {
            continue;
        }
	    //调试
	    //cout<<iter->path().string()<<endl;
        x->push_back(iter->path().string());
    }
    return true;
};

static bool title_parse(const string&file,string*title)
{
    size_t begin=file.find("<title>");
    if(begin==string::npos)
    {
        return false;
    }
    size_t end =file.find("</title>");
    if(end==string::npos)
    {
        return false;
    }
    begin+=string("<title>").size();
    if(begin>=end) return false;
    *title=file.substr(begin,end-begin);
    return true;
}

bool content_parse(const string &file,string*out)
{  
    enum status{
        LABLE,
        CONTENT
    };
    enum status s=LABLE;
    for(char a:file)
    {
        switch(s){
            case LABLE:
                if(a=='>') s=CONTENT;
                break;
            case CONTENT:
                 if(a=='<') s=LABLE;
                 else{
                    if(a=='\n') a=' ';
                    out->push_back(a);
                 } 
                 break;
            default:
                break;
        }
    }
    return true;
}
static void show_url(const x_t& h )
{
    cout<<"title:"<<h.title<<endl<<endl;
    cout<<"content:"<<h.content<<endl<<endl;
    cout<<"url: "<<h.url<<endl;
    cout<<endl;
}

bool url_parse(const string &file_path,string*out)
{
    //官网文件路径与拷贝复制的路径有相关性
    string  url_head="https://boost.ac.cn/doc/libs/1_88_0/doc/html";
    string  url_tail=file_path.substr(src_input.size());
    *out=url_head+url_tail;
    return true;
}

//进行解析
bool em_analysis(const vector<string>&x,vector<x_t>*y)
{
      for(const string & file_path :x)
      {
        //先进行读取文件操作
        string result;
        if(!tool_a::file_tool::ReadFile(file_path,&result))
        {
            continue;
        }
        x_t p;
        //进行标题解析
        if(!title_parse(result,&p.title))
        {
           continue;
        }
        //进行内容解析
        if(!content_parse(result,&p.content))
        {
            continue;
        }
        //进行url解析
        if(!url_parse(result,&p.url))
        {
            continue;
        }
        //show_url(p);
        y->push_back(move(p));
      }
      return true;
};

//将解析结果保存
bool em_out(vector<x_t>&x,const string&y)
{
#define SEP '\3'
    std::ofstream out(y, std::ios::out | std::ios::binary);
    if(!out.is_open())
    {
        cerr<<"out open fail"<<y<<endl;
        return false;
    }
    //对保存的内容进行填充
    for(const auto& item:x)
    {
        string out_string;
        out_string=item.title;
        out_string+=SEP;
        out_string+=item.content;
        out_string+=SEP;
        out_string+=item.url;
        out_string+='\n';
        out.write(out_string.c_str(),out_string.size());
    }
    out.close();
    return true;
};

int main()
{
    vector<string>files_list;
    //进行文件放入到vector
    if(!em_in(&files_list,src_input))
    {
       cerr<<"file enum fail!"<<endl;
        return 1;
    }
    vector<x_t>results;
    //读取文件内容，进行解析
    if(!em_analysis(files_list,&results))
    {
        cerr<<"file analysis fail!"<<endl;
        return 2;
    }
    //解析成功，放入到文件里面
    if(!em_out(results,src_output))
    {
        cerr<<"file put fail!"<<endl;
        return 3;
    }
    return 0;
}
